using CoreProject.Model;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;

namespace CoreProject.Repository
{
    public class BaseRepository<T> where T : class
    {
        internal readonly EFDbContext _context;
        internal readonly DbSet<T> _dbSet;

        public BaseRepository(EFDbContext context)
        {
            _context = context;
            _dbSet = _context.Set<T>();
        }

        /// <summary>
        /// 单条数据查询
        /// </summary>
        /// <param name="whereLambda"></param>
        /// <returns></returns>
        public virtual async Task<T> GetAsync(Expression<Func<T, bool>> whereLambda)
        {
            return await _dbSet.AsNoTracking().Where(whereLambda).FirstAsync();
        }

        /// <summary>
        /// 全部数据查询
        /// </summary>
        /// <typeparam name="S"></typeparam>
        /// <param name="isAsc"></param>
        /// <param name="orderLambda"></param>
        /// <param name="whereLambda"></param>
        /// <returns></returns>
        public virtual async Task<List<T>> GetListAsync<S>(bool isAsc,
            Expression<Func<T, S>> orderLambda, Expression<Func<T, bool>> whereLambda)
        {
            var data = _dbSet.AsNoTracking().Where(whereLambda);
            if (isAsc)
                data = data.OrderBy<T, S>(orderLambda);
            else
                data = data.OrderByDescending<T, S>(orderLambda);
            return await data.ToListAsync();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="S"></typeparam>
        /// <param name="page"></param>
        /// <param name="sizie"></param>
        /// <param name="isAsc"></param>
        /// <param name="orderLambda"></param>
        /// <param name="whereLambda"></param>
        /// <returns></returns>
        public virtual async Task<(List<T> list, int count)> GetListByPageAsync<S>(int page, int sizie, bool isAsc,
            Expression<Func<T, S>> orderLambda, Expression<Func<T, bool>> whereLambda)
        {
            var data = _dbSet.AsNoTracking().Where(whereLambda);
            var count = data.Count();
            if (isAsc)
                data = data.OrderBy<T, S>(orderLambda);
            else
                data = data.OrderByDescending<T, S>(orderLambda);
            List<T> list = await data.Skip<T>((page - 1) * sizie).Take<T>(sizie).ToListAsync();

            return (list, count);
        }

        /// <summary>
        /// 增加
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual async Task<bool> AddAsync(T t)
        {
            //附加
            _dbSet.Attach(t);
            _context.Entry(t).State = EntityState.Added;
            return await _context.SaveChangesAsync() > 0;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual async Task<bool> UpdateAsync(T t)
        {
            //附加
            _dbSet.Attach(t);
            _context.Entry(t).State = EntityState.Modified;
            return await _context.SaveChangesAsync() > 0;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteAsync(T t)
        {
            //附加
            _dbSet.Attach(t);
            _context.Entry(t).State = EntityState.Deleted;
            return await _context.SaveChangesAsync() > 0;
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteRangeAsync(T[] ts)
        {
          //附加
          //_dbSet.AttachRange(ts);
          //_context.Entry(ts).State = EntityState.Deleted;

          foreach (var t in ts)
          {
            _dbSet.Attach(t);
            _context.Entry(t).State = EntityState.Deleted;
          }

          return await _context.SaveChangesAsync() > 0;
        }
  }
}
